home *** CD-ROM | disk | FTP | other *** search
/ 9-Digit Zip Code Directory / 9-Digit Zip Code Directory (American Business Information) (ABIZIP-12).ISO / z4src.zip / CPNYBBLE.C < prev    next >
C/C++ Source or Header  |  1993-07-07  |  9KB  |  321 lines

  1. //----------------------------------------------------------------------------
  2. //                            MODULE DESCRIPTION
  3. //
  4. //  Module:    cbnybble.c
  5. //   Title:    Data Compression Library
  6. //  Notice:    John M. Weeder
  7. //                 Copyright (c) 1993. All rights reserved.
  8. //             This module contains proprietary information and should be 
  9. //                treated as confidential.
  10. //
  11. //----------------------------------------------------------------------------
  12. //                           MAINTENANCE HISTORY
  13. //
  14. // $Workfile$
  15. // $Revision$
  16. //   $Author$
  17. //     $Date$
  18. //      $Log$    
  19. //
  20. //----------------------------------------------------------------------------
  21. //                             MODULE NARRATIVE
  22. //
  23. //
  24. //    This module contains code to encode a string on a nybble by nybble basis.
  25. //
  26. // Note the 0x80 bit of the first byte in a nybble encoded string is never
  27. //    set. This differentiates a nybble encoded string from a cached word.
  28. //
  29. //    The code in this module should be written entirely in C. 
  30. //    Do not use any C++ constructs.
  31. //
  32. //    This module is portable to:
  33. //        DOS 3.X+
  34. //        MS Windows 3.X+
  35. //        OS/2 2.X+
  36. //        OS/2 2.0 PM
  37. //        SCO UNIX.
  38. //
  39. //    The following compilers are supported:
  40. //        MSC 6.0A
  41. //        MSC/C++ 7.0
  42. //        Borland C++ 3.1 for DOS
  43. //        Borland C++ 1.0 for OS/2 2.X
  44. //        SCO UNIX cc
  45. //
  46. //----------------------------------------------------------------------------
  47. #include <cp.h>
  48.  
  49. //----------------------------------------------------------------------------
  50. //    Compression tables
  51. //    Order of characters within each level is important to search speed while
  52. //    encoding.
  53. //----------------------------------------------------------------------------
  54. static CHAR achLevel1[15] =                // These characters are stored in 1 nybble
  55.     {
  56.    'E',
  57.    'A',
  58.    'O',
  59.    'I',
  60.    'U',
  61.     'S',
  62.    'T',
  63.    'R',
  64.    'L',
  65.    'N',
  66.    'D',
  67.    'M',
  68.    'C',
  69.    'P',
  70.    'H',
  71.     };
  72. static CHAR achLevel2[15] =                // These characters are stored in 2 nybbles
  73.     {                                                // All others are stored in 3 nybbles
  74.    'F',
  75.    'B',
  76.    'W',
  77.    'Y',
  78.    'K',
  79.    'G',
  80.    'V',
  81.    'J',
  82.    'X',
  83.    'Q',
  84.    'Z',
  85.    '-',
  86.    '/',
  87.    '#',
  88.    '&'
  89.     };
  90.  
  91.  
  92. //----------------------------------------------------------------------------
  93. //    Macros
  94. //----------------------------------------------------------------------------
  95. //
  96. //    Macro to read a nybble from the byte stream
  97. //
  98. #define NybbleInput()            if (fNybble)                                    \
  99.                                     {                                                \
  100.                                             bVal = (BYTE)((*pbDecode) & 0x0F);    \
  101.                                             pbDecode++;                                  \
  102.                                             }                                   \
  103.                                         else                                   \
  104.                                             {                                              \
  105.                                             bVal = (BYTE)((*pbDecode) >> 4);        \
  106.                                             cDecode++;                                    \
  107.                                     }                                                \
  108.                                 fNybble = !fNybble;
  109.  
  110. //
  111. //    Macro to write a nybble to the byte stream
  112. //
  113. #define NybbleOutput()            if (fNybble)                                  \
  114.                                    {                                              \
  115.                                    *pbEncode |= bVal;                      \
  116.                                             pbEncode++;                                  \
  117.                                    }                                              \
  118.                                else                                              \
  119.                                             {                                              \
  120.                                    *pbEncode = (BYTE)(bVal << 4);      \
  121.                                    cEncode++;                                  \
  122.                                             }                                              \
  123.                                 fNybble = !fNybble;
  124.  
  125.  
  126. //----------------------------------------------------------------------------
  127. //   Description:    Decode a buffer
  128. //    Parameters:    pbDecode            Pointer to buffer to decode.
  129. //                        pcDecode            Pointer to receive number of bytes decoded.
  130. //                        pch                Buffer to place decoded text into.
  131. //                                            Null terminator is added to buffer.
  132. //                                            Buffer is assumed to be of sufficient size.
  133. //       Returns:    TRUE if successful.
  134. //----------------------------------------------------------------------------
  135. BOOL FN_E NybbleDecode(PBYTE pbDecode, PSIZET pcDecode, PCHAR pch)
  136. {
  137.     SIZET cChars;
  138.     SIZET cDecode = 0;
  139.     BOOL fNybble = FALSE;
  140.     BYTE bVal;
  141.  
  142.     Assert(pbDecode && pcDecode && pch);
  143.     Assert(*pbDecode && *pbDecode <= 0x7F);
  144.     if (*pbDecode == 0x7F)                    // Unencoded ASCII string!
  145.         {
  146.         strcpy(pch, (PSZ)(pbDecode + 1));
  147.         *pcDecode = strlen((PSZ)(pbDecode + 1)) + 2;
  148.         return TRUE;
  149.         }
  150.  
  151.     cChars = (SIZET)*pbDecode;                // Check decode length
  152.     pbDecode++;
  153.     cDecode++;
  154.     for (; cChars; cChars--)
  155.         {
  156.         NybbleInput();
  157.         if (bVal)
  158.             {
  159.             *pch++ = achLevel1[bVal-1];
  160.             }
  161.         else
  162.             {
  163.             NybbleInput();
  164.             if (bVal)                        // Input a 1 byte character
  165.                 {
  166.                 *pch++ = achLevel2[bVal-1];
  167.                 }
  168.             else
  169.                 {
  170.                 NybbleInput();                    // Input a 2 byte character
  171.                 *pch = (CHAR)(BYTE)(bVal << 4);
  172.                 NybbleInput();
  173.                 *pch |= bVal;
  174.                 pch++;                            // Move to next
  175.                 }
  176.             }
  177.         }
  178.     *pcDecode = cDecode;
  179.     pch[0] = '\0';                                // Add null terminator
  180.     return TRUE;
  181. }
  182.  
  183.  
  184. //----------------------------------------------------------------------------
  185. //   Description:    Encode a buffer
  186. //                          The first byte contains the length of the encoded string.
  187. //                        This length must be < 0x7F, since the 0x80 bit may not
  188. //                        be set.
  189. //                        If the length is 0x7F, the string is not encoded, but is
  190. //                        stored as an ASCII zero terminated string. This is done
  191. //                        because the encoded string took more space than the
  192. //                        un-encoded string.
  193. //    Parameters:    pbEncode            Pointer to buffer to encode into.
  194. //                        pcEncode            Pointer to variable to recieve size of 
  195. //                                            encoded text.
  196. //                                            Buffer must be of sufficient size.
  197. //                                            Maximum size is strlen(pcsz)+2.
  198. //                        pcsz                Buffer to read text from.
  199. //       Returns:    TRUE if successful.
  200. //----------------------------------------------------------------------------
  201. BOOL FN_E NybbleEncode(PBYTE pbEncode, PSIZET pcEncode, PCSZ pcsz)
  202. {
  203.     SIZET cEncode = 1;
  204.     SIZET i;
  205.     BYTE bVal;
  206.     BOOL fNybble = FALSE;
  207.     SIZET cMaxEncode;
  208.     PBYTE pbSave = pbEncode;
  209.     PCSZ pcszSave = pcsz;
  210.  
  211.     Assert(pbEncode && pcEncode && pcsz && pcsz[0]);
  212.     cMaxEncode = strlen(pcsz);
  213.     Assert(cMaxEncode && cMaxEncode < 0x7F);
  214.     *pbEncode = (BYTE)cMaxEncode;
  215.     pbEncode++;
  216.     cMaxEncode += 2;
  217.     for (; pcsz[0];)
  218.         {                                            // Try to encode into first level
  219.         for (i = 0; i < 15; ++i)
  220.             if (achLevel1[i] == pcsz[0])
  221.                 break;
  222.  
  223.         if (i >= 15)
  224.             {
  225.             bVal = (BYTE)0;
  226.             NybbleOutput();
  227.             if (cEncode == cMaxEncode)
  228.                 break;
  229.  
  230.             for (i = 0; i < 15; ++i)        // Encode to second level
  231.                 if (achLevel2[i] == pcsz[0]) 
  232.                     break;
  233.  
  234.             if (i >= 15)
  235.                 {
  236.                 bVal = 0;                        // Level 3 (2 bytes)
  237.                 NybbleOutput();
  238.                 if (cEncode == cMaxEncode)
  239.                     break;
  240.                 bVal = (BYTE)(pcsz[0] >> 4);
  241.                 NybbleOutput();
  242.                 if (cEncode == cMaxEncode)
  243.                     break;
  244.                 bVal = (BYTE)(pcsz[0] & 0x0F);
  245.                 NybbleOutput();
  246.                 if (cEncode == cMaxEncode)
  247.                     break;
  248.                 }
  249.             else
  250.                 {
  251.                 bVal = (BYTE)(i + 1);        // Level 1 (2 nybbles)
  252.                 NybbleOutput();                    
  253.                 if (cEncode == cMaxEncode)
  254.                     break;
  255.                 }
  256.             }
  257.         else
  258.             {
  259.             bVal = (BYTE)(i + 1);            // Level 1 (1 nybble)
  260.             NybbleOutput();                    
  261.             if (cEncode == cMaxEncode)
  262.                 break;
  263.             }
  264.         pcsz++;
  265.         }
  266.     if (cEncode >= cMaxEncode)
  267.         {
  268.         *pbSave = (BYTE)0x7F;                // Copy string and null
  269.         strcpy((PSZ)(pbSave + 1), pcszSave);
  270.         cEncode = cMaxEncode;
  271.         }
  272.     *pcEncode = cEncode;                        // Return length of encoded string
  273.     return TRUE;
  274. }
  275.  
  276.  
  277. //----------------------------------------------------------------------------
  278. //   Description:    Run standard test suite
  279. //    Parameters:    sTest        Test to run.
  280. //                                        0        Run all default tests (except).
  281. //       Returns:    TRUE if successful.
  282. //----------------------------------------------------------------------------
  283. #if COMPILE_TEST
  284. BOOL FN NybbleTest(SHORT sTest)
  285. {
  286. static CHAR szBuf[80];
  287. static BYTE bBuf[80];
  288. static PSZ apsz[] =
  289.     {
  290.     "EAOIUSTRLNDMCPH",                        // All nybble
  291.     "FBWYKGVJXQZ-/#&",                        // All byte
  292.     "1234567890",                                // 2 Byte
  293.     "E",                                            // Single char
  294.     "F",                                            // Single char
  295.     "1",                                            // Single char
  296.     "EF1B2AB2OWW3IIY4UK5SG6TV7",            // A mix
  297.     NULL
  298.     };
  299.     SIZET i;
  300.     SIZET cEncode, cDecode;
  301.  
  302.     NOTUSED(sTest);
  303.     for (i = 0; apsz[i]; ++i)
  304.         {
  305.         NybbleEncode(bBuf, &cEncode, apsz[i]);
  306.         Output(" Input: (%3d) %s\n", strlen(apsz[i])+1, apsz[i]);
  307.         NybbleDecode(bBuf, &cDecode, szBuf);
  308.         Output("Output: (%3d) %s\n", strlen(szBuf)+1,   szBuf);
  309.         Output(" Bytes:  %3d\n", cEncode);
  310.         if (cEncode != cDecode
  311.         || strcmp(apsz[i], szBuf) != 0)
  312.             return FALSE;
  313.         }
  314.     return TRUE;
  315. }
  316. #endif
  317. //----------------------------------------------------------------------------
  318. //------------------------------- End of File --------------------------------
  319. //----------------------------------------------------------------------------
  320.  
  321.